/*
 *  Copyright (C) 2010 Martin Haulrich <mwh.isv@cbs.dk>
 *
 *  This file is part of the MatrixParser package.
 *
 *  The MatrixParser program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.osdtsystem.matrixparser.featureextraction;

import org.osdtsystem.matrixparser.data.CONLLSentence;
import org.osdtsystem.matrixparser.data.CONLLToken;
import org.osdtsystem.matrixparser.features.FeatureVector;
import org.osdtsystem.matrixparser.parsers.ParsingModel;
import org.osdtsystem.matrixparser.parsers.output.DependencyTree;

/**
 *
 * @author Martin Haulrich
 */
public class FirstOrderExtractorUnlabelledNew extends AbstractFirstOrderExtractor
        implements FirstOrderExtractorUnlabelled {
    public FirstOrderExtractorUnlabelledNew(ParsingModel model) {
        super(model);
    }

    public void extract(FeatureVector fv, DependencyTree tree, int node) {
        extractUnlabelled(fv, tree.sentence(), tree.head(node), node);
    }

    @Override
    public void extractUnlabelled(FeatureVector fv, CONLLSentence sentence, int head, int dep) {
        int dist = Math.abs(head - dep);
        String distBool;
        if (dist > 10) {
            distBool = "10";
        } else if (dist > 5) {
            distBool = "5";
        } else {
            distBool = "" + (dist - 1);
        }

        String dir = (head > dep) ? "LA" : "RA";

//        String dirDist = "|" + dir + "|" + distBool;
        String dirDist = "&" + dir + "&" + distBool;

        int small = (head < dep) ? head : dep;
        int large = (head > dep) ? head : dep;

        addLinearFeatures("POS", sentence, CONLLToken.POSTAG, dirDist, small, large, fv);
        addLinearFeatures("CPOS", sentence, CONLLToken.CPOSTAG, dirDist, small, large, fv);

        CONLLToken headToken = sentence.words.get(head);
        CONLLToken depToken = sentence.words.get(dep);
        addTwoObsFeatures("HC",
                headToken.get(CONLLToken.FORM), headToken.get(CONLLToken.POSTAG),
                depToken.get(CONLLToken.FORM), depToken.get(CONLLToken.POSTAG),
                dirDist, fv);

        addTwoObsFeatures("HCA",
                headToken.get(CONLLToken.FORM), headToken.get(CONLLToken.CPOSTAG),
                depToken.get(CONLLToken.FORM), depToken.get(CONLLToken.CPOSTAG),
                dirDist, fv);

        addTwoObsFeatures("HCC",
                headToken.get(CONLLToken.LEMMA), headToken.get(CONLLToken.POSTAG),
                depToken.get(CONLLToken.LEMMA), depToken.get(CONLLToken.POSTAG),
                dirDist, fv);


        addTwoObsFeatures("HCD",
                headToken.get(CONLLToken.LEMMA), headToken.get(CONLLToken.CPOSTAG),
                depToken.get(CONLLToken.LEMMA), depToken.get(CONLLToken.CPOSTAG),
                dirDist, fv);

        String headFeaturesString = headToken.get(CONLLToken.FEATS);
        String[] headFeatures = headFeaturesString.split("\\|");

        String depFeaturesString = depToken.get(CONLLToken.FEATS);
        String[] depFeatures = depFeaturesString.split("\\|");
//        System.err.println(headFeatures.length + "  " + depFeatures.length);

        for (int i = 0; i < headFeatures.length; i++) {
            for (int j = 0; j < depFeatures.length; j++) {
                addTwoObsFeatures("FF" + i + "*" + j,
                        headToken.get(CONLLToken.FORM), headFeatures[i],
                        depToken.get(CONLLToken.FORM), depFeatures[j],
                        dirDist, fv);
                addTwoObsFeatures("LF" + i + "*" + j,
                        headToken.get(CONLLToken.LEMMA), headFeatures[i],
                        depToken.get(CONLLToken.LEMMA), depFeatures[j],
                        dirDist, fv);
            }
        }

        // We only want unknown counted once
        if (fv.getValue(featureHandler.UNKNOWN) != 0) {
            fv.setValue(featureHandler.UNKNOWN, 1);
        }
    }

    private void addLinearFeatures(String type, CONLLSentence sentence, int typeIndex, String dirDist, int first, int second, FeatureVector fv) {
//        System.out.println("HOOH");

//        System.out.println(type + " " + first + " " + second + dirDist);

        String pLeft = first > 0 ? sentence.words.get(first - 1).tokens.get(typeIndex) : "STR";
        String pRight = second < sentence.words.size() - 1 ? sentence.words.get(second + 1).tokens.get(typeIndex) : "END";
        String pLeftRight = first < second - 1 ? sentence.words.get(first + 1).tokens.get(typeIndex) : "MID";
        String pRightLeft = second > first + 1 ? sentence.words.get(second - 1).tokens.get(typeIndex) : "MID";

        String firstType = sentence.words.get(first).tokens.get(typeIndex);
        String secondType = sentence.words.get(second).tokens.get(typeIndex);
        String group = type + "PC=";

        for (int i = first + 1; i < second; i++) {
            String iType = sentence.words.get(i).get(typeIndex);
            add(fv, group, firstType, secondType, iType);
            add(fv, group, firstType, secondType, iType, dirDist);
        }

        addCorePosFeatures(type + "PT", pLeft, firstType, pLeftRight,
                pRightLeft, secondType, pRight, dirDist, fv);
    }

    private void addCorePosFeatures(String prefix,
            String leftOf1, String one, String rightOf1,
            String leftOf2, String two, String rightOf2,
            String dirDist, FeatureVector fv) {

        add(fv, prefix + "1=", leftOf1, one, two);
        add(fv, prefix + "1=", leftOf1, one, two, dirDist);
        add(fv, prefix + "1=", leftOf1, one, two, rightOf2);
        add(fv, prefix + "1=", leftOf1, one, two, rightOf2, dirDist);

        add(fv, prefix + "2=", leftOf1, two, rightOf2);
        add(fv, prefix + "2=", leftOf1, two, rightOf2, dirDist);

        add(fv, prefix + "3=", leftOf1, one, rightOf2);
        add(fv, prefix + "3=", leftOf1, one, rightOf2, dirDist);

        add(fv, prefix + "4=", one, two, rightOf2);
        add(fv, prefix + "4=", one, two, rightOf2, dirDist);

        /////////////////////////////////////////////////////////////
        prefix = "A" + prefix;

        // feature posL posL+1 posR-1 posR
        add(fv, prefix + "1=", one, rightOf1, leftOf2);
        add(fv, prefix + "1=", one, rightOf1, leftOf2, dirDist);
        add(fv, prefix + "1=", one, rightOf1, leftOf2, two);
        add(fv, prefix + "1=", one, rightOf1, leftOf2, two, dirDist);

        add(fv, prefix + "2=", one, rightOf1, two);
        add(fv, prefix + "2=", one, rightOf1, two, dirDist);

        add(fv, prefix + "3=", one, leftOf2, two);
        add(fv, prefix + "3=", one, leftOf2, two, dirDist);

        add(fv, prefix + "4=", rightOf1, leftOf2, two);
        add(fv, prefix + "4=", rightOf1, leftOf2, two, dirDist);

        ///////////////////////////////////////////////////////////////
        prefix = "B" + prefix;

        //// feature posL-1 posL posR-1 posR
        add(fv, prefix + "1=", leftOf1, one, leftOf2, two);
        add(fv, prefix + "1=", leftOf1, one, leftOf2, two, dirDist);

        //// feature posL posL+1 posR posR+1
        add(fv, prefix + "2=", one, rightOf1, two, rightOf2);
        add(fv, prefix + "2=", one, rightOf1, two, rightOf2, dirDist);

    }

    private void addTwoObsFeatures(String prefix,
            String item1F1, String item1F2,
            String item2F1, String item2F2,
            String attachDistance,
            FeatureVector fv) {

        add(fv, prefix + "2FF1=", item1F1);
        add(fv, prefix + "2FF1=", item1F1, attachDistance);

        add(fv, prefix + "2FF1=", item1F1, item1F2);
        add(fv, prefix + "2FF1=", item1F1, item1F2, attachDistance);

        add(fv, prefix + "2FF1=", item1F1, item1F2, item2F2);
        add(fv, prefix + "2FF1=", item1F1, item1F2, item2F2, attachDistance);

        add(fv, prefix + "2FF1=", item1F1, item1F2, item2F2, item2F1);
        add(fv, prefix + "2FF1=", item1F1, item1F2, item2F2, item2F1, attachDistance);

        add(fv, prefix + "2FF2=", item1F1, item2F1);
        add(fv, prefix + "2FF2=", item1F1, item2F1, attachDistance);

        add(fv, prefix + "2FF3=", item1F1, item2F2);
        add(fv, prefix + "2FF3=", item1F1, item2F2, attachDistance);

        add(fv, prefix + "2FF4=", item1F2, item2F1);
        add(fv, prefix + "2FF4=", item1F2, item2F1, attachDistance);

        add(fv, prefix + "2FF4=", item1F2, item2F1, item2F2);
        add(fv, prefix + "2FF4=", item1F2, item2F1, item2F2, attachDistance);

        add(fv, prefix + "2FF5=", item1F2, item2F2);
        add(fv, prefix + "2FF5=", item1F2, item2F2, attachDistance);

        add(fv, prefix + "2FF6=", item2F1, item2F2);
        add(fv, prefix + "2FF6=", item2F1, item2F2, attachDistance);

        add(fv, prefix + "2FF7=", item1F2);
        add(fv, prefix + "2FF7=", item1F2, attachDistance);

        add(fv, prefix + "2FF8=", item2F1);
        add(fv, prefix + "2FF8=", item2F1, attachDistance);

        add(fv, prefix + "2FF9=", item2F2);
        add(fv, prefix + "2FF9=", item2F2, attachDistance);
    }
}
